package com.bowen.demo.demo007;

/**
 * 验证volatile的可见性
 * 1.当number未被volatile修饰时，new Thread将number值改为60，但main线程并不知道，会一直在循环中出不来
 * 2.当number使用volatile修饰，new Thread改变number值后，会通知main线程主内存的值已被修改，结束任务。体现了可见性

 * 验证volatile不保证原子性
 * 1.原子性是指，某个线程在执行某项业务时，中间不可被加塞或分割，需要整体完整。要么同时成功，要么同时失败
 * 如何解决呢？
 * 1.使用synchronize
 * 2.使用AtomicInteger
 */
public class VolatileDemo {

	public static void main(String[] args) {
		//seeByVolatile();
		atomic();
	}

	//验证原子性
	public static void atomic() {
		MyData myData = new MyData();
		for (int i = 1; i <= 20; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					for (int j = 1; j <= 1000; j++) {
                        /*synchronized (myData.object){
                            myData.addPlusPlus();
                        }*/
						myData.addPlusPlus();
						myData.addAtomic();
					}
				}
			}).start();
		}

		//等待上面20个线程全部计算结束
		while (Thread.activeCount() > 2){
			Thread.yield();
		}

		System.out.println(Thread.currentThread().getName() + "int finally number is " + myData.number);
		System.out.println(Thread.currentThread().getName() + "AtomicInteger finally number is " + myData.atomicInteger);
	}

	//验证可见性的方法
	public static void seeByVolatile() {
		MyData myData = new MyData();
		//第一个线程
		new Thread(){
			@Override
			public void run(){
				System.out.println(Thread.currentThread().getName() + " come in");
				try {
					sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				myData.addTo60();
				System.out.println(Thread.currentThread().getName() + " update number to " + myData.number);
			}
		}.start();

		//第二个线程 main
		while (myData.number == 0){
			//System.out.println("number为0");
		}
		System.out.println(Thread.currentThread().getName() + "mission is over");
	}
}